﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using GameEngine;
using CXEngineWrapper;

namespace DaphneWin8.Common
{
    public class EngineMoveConverter
    {
        private class Pos
        {
            public Position Position;
            public enumFigureType FigureType;
        }

        private GameBoard _gameBoard;

        public EngineMoveConverter()
        {
        }

        public OutputBitBoard[] ConvertMoveHistory(List<Move> lstGameHistory, GameBoard gameBoard)
        {
            List<OutputBitBoard> list = new List<OutputBitBoard>();

            OutputBitBoard obb;
            foreach (var move in lstGameHistory)
            {
                obb =  new OutputBitBoard();
                obb.wm = (uint)move.bitOriginalPosition.bitWM;
                obb.wk = (uint)move.bitOriginalPosition.bitWQ;
                obb.bm = (uint)move.bitOriginalPosition.bitWM;
                obb.bk = (uint)move.bitOriginalPosition.bitBQ;

                list.Add(obb);
            }

            BitBoard bitOrig = gameBoard.PackGameBoard();
            obb = new OutputBitBoard();
            obb.wm = (uint)bitOrig.bitWM;
            obb.wk = (uint)bitOrig.bitWQ;
            obb.bm = (uint)bitOrig.bitWM;
            obb.bk = (uint)bitOrig.bitBQ;

            list.Add(obb);

            return list.ToArray();

        }

        public Coordinate[] ConvertBoard(GameBoard gameBoard)
        {
            _gameBoard = gameBoard;
            Coordinate[] board = new Coordinate[gameBoard.Size * gameBoard.Size];

            for(int row = 0; row < gameBoard.Size; row++)
                for (int col = 0; col < gameBoard.Size; col++)
                {
                    eFigureType dstFigType = eFigureType.Nothing;
                    enumFigureType srcFigType = _gameBoard.GetField(row, col);

                    switch(srcFigType)
                    {
                        case enumFigureType.WhiteMan:
                            dstFigType = eFigureType.WhiteMan;
                            break;
                        case enumFigureType.WhiteKing:
                            dstFigType = eFigureType.WhiteKing;
                            break;
                        case enumFigureType.BlackMan:
                            dstFigType = eFigureType.BlackMan;
                            break;
                        case enumFigureType.BlackKing:
                            dstFigType = eFigureType.BlackKing;
                            break;
                    }

                    board[row * gameBoard.Size + col] = new Coordinate(row, col, dstFigType);
                }

            return board;
        }

        public List<Position> Convert(OutputBitBoard bb, GameBoard gameboard)
        {
            _gameBoard = gameboard;

            // convert positions
            List<Pos> posList = ConvertPositions(bb);

            // find start position
            Pos startPos = FindFirstPosition(posList);
            //if (startPos == null)
                //throw new ApplicationException("TO-DO: circular moves");
            
            // find end position
            Pos endPos = FindEndPosition(posList, startPos);
            if (endPos == null)
                throw new ArgumentNullException("endPos");

            // remove source and target
            posList.Remove(startPos);
            posList.Remove(endPos);

            // find path
            var pathList = FindPath(startPos, endPos, posList);

            List<Position> result = new List<Position>();
            result.Add(startPos.Position);
            result.AddRange(pathList);
            result.Add(endPos.Position);

            return result;
        }

        private List<Position> FindPath(Pos startPos, Pos endPos, List<Pos> inList)
        {
            List<Position> outList = new List<Position>();

            Position lastPos = startPos.Position;

            while (inList.Count > 1)
            {
                // find move in direction
                Position inDir = Position.Empty;
                Pos inDirPos = null;
                int iMoveLength = int.MaxValue;
                foreach(var item in inList)
                    if (item.Position.IsDiagonal(lastPos))
                    {
                        int iLength = Math.Abs(item.Position.Row - lastPos.Row);
                        if (iLength < iMoveLength)
                        {
                            inDir = item.Position;
                            inDirPos = item;
                            iMoveLength = iLength;
                        }
                    }
                //if (inDir == Position.Empty)
                //    throw new ApplicationException("Position Empty");
                
                inList.Remove(inDirPos);
                enumDiagonalDir direction = lastPos.GetDiagonalDir(inDir);

                // find next diagonal
                bool bFound = false;
                while (_gameBoard.IsOutsideBoard(inDir) == false)
                {
                    inDir = inDir.GetNextField(direction);

                    foreach (var item in inList)
                        if (item.Position.IsDiagonal(inDir))
                        {
                            bFound = true;
                            break;
                        }
                    if (bFound == true)
                        break;
                }

                outList.Add(inDir);
                lastPos = inDir;
            }

            return outList;
        }

        private Pos FindEndPosition(List<Pos> list, Pos startPos)
        {
            foreach(var item in list)
                if (startPos.Position != item.Position)
                {
                    if (startPos.FigureType.FigureColor() == item.FigureType.FigureColor())
                        return item;
                }

            return null;
        }

        private Pos FindFirstPosition(List<Pos> list)
        {
            foreach (var item in list)
            {
                if (_gameBoard.GetField(item.Position) != enumFigureType.Nothing
                    && _gameBoard.GetField(item.Position).FigureColor() == _gameBoard.OnMove)
                    return item;
            }

            return null;
        }


        private List<Pos> ConvertPositions(OutputBitBoard bb)
        {
            List<Pos> list = new List<Pos>();

            int shift = 0;

            for (int row = 0; row < _gameBoard.Size; row++)
                for (int col = 0; col < _gameBoard.Size; col++)
                {
                    if (_gameBoard.GetFieldColor(row, col) == enumFigureColor.Black)
                    {
                        Position position = new Position(row, col);
                        enumFigureType fig = enumFigureType.Nothing;

                        if ((bb.wm & ((uint)1 << shift)) != 0)
                            fig = enumFigureType.WhiteMan;
                        else if ((bb.wk & ((uint)1 << shift)) != 0)
                            fig = enumFigureType.WhiteKing;
                        else if ((bb.bm & ((uint)1 << shift)) != 0)
                            fig = enumFigureType.BlackMan;
                        else if ((bb.bk & ((uint)1 << shift)) != 0)
                            fig = enumFigureType.BlackKing;

                        if (fig != enumFigureType.Nothing)
                        {
                            Pos pos = new Pos();
                            pos.Position = position;
                            pos.FigureType = fig;
                            list.Add(pos);
                        }

                        shift++;
                    }
                }

            return list;
        }


    }
}
